package xutil

import (
	"errors"
	"fmt"
	"log"
	"os"
	"sync"
	"time"
)

// Logger 日志，实现了Write接口

type Logger struct {
	t  time.Time
	fp *os.File
	l  int //当前是第几个日志
	un string
	m  sync.RWMutex
}

func F判断目录是否存在不存在则创建(dirPath string) (err error) {
	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
		// 目录不存在，创建目录
		err := os.MkdirAll(dirPath, os.ModePerm)
		if err != nil {
			log.Fatalf("无法创建目录: %v", err)
		}
		//log.Println("目录创建成功:", dirPath)
	} else {
		// 目录存在
		//log.Println("目录已存在:", dirPath)
	}
	return
}

func (l *Logger) Printf(format string, a ...interface{}) (n int, err error) {
	key := fmt.Sprintf(format, a...) //先生成产品的key
	return l.F打印并且发送消息(key)
}

// 日志输出字符串
func (l *Logger) Println(inter ...interface{}) (n int, err error) {
	var ll string
	for range inter {
		ll += "%v"
	}
	key := fmt.Sprintf(ll, inter...) //先生成产品的key
	return l.addtimeWrite(key)
}

func (l *Logger) F打印并且发送消息(inter ...interface{}) (n int, err error) {
	var ll string
	for range inter {
		ll += "%v"
	}
	key := fmt.Sprintf(ll, inter...) //先生成产品的key
	return l.addtimeWrite(key)
}

func (l *Logger) addtimeWrite(str string) (n int, err error) {
	key := time.Now().Format("2006-01-02 - 15:04:05")
	key += " | " + str + "\n"

	return l.Write([]byte(key))
}

// Write 实现Write接口，用于写入
func (l *Logger) Write(p []byte) (n int, err error) {
	today := dateToStr(time.Now())
	loggerDate := dateToStr(l.t)

	//如果当前日期与logger日期不一致，表示是新的一天，需要关闭原日志文件，并更新日期与日志文件
	if today != loggerDate && l.fp != nil {
		l.fp.Close()
		l.l = 1
		l.fp = nil
	}
	//如果文件的尺寸大于100M,那么重新弄一个日志，并且把老的压缩一下
	if l.fp != nil {
		fs, _ := l.fp.Stat()
		if fs.Size() > 100*1024*1024 {
			l.fp.Close()
			l.l += 1
			l.fp = nil
			//l.setLogfile()
		}
	}

	if l.fp == nil {
		l.setLogfile()
	}

	//写入
	if l.fp != nil {
		return l.fp.Write(p)
	}

	return 0, errors.New("无法写入日志")
}

// new 初始化
func F新建日志() *Logger {
	l := &Logger{
		t: time.Now(),
		l: 1,
	}
	l.setLogfile()
	return l
}

// setLogfile 更新日志文件
func (l *Logger) setLogfile() error {
	year, month, day := time.Now().Date()
	dir := fmt.Sprintf("log/%d%02d", year, month)

	//锁住，防止并发时，多次执行创建。os.MkdirAll在目录存在时，也不会返回错误，锁不锁都行
	l.m.Lock()
	defer l.m.Unlock()
	if !IsDir(dir) {
		err := os.MkdirAll(dir, 0755)
		return err
	}

	newname := fmt.Sprintf("%s/%02d.%02d.log", dir, day, l.l)
	//如果上个文件存在并且跟新的不一样，那么进行一下压缩
	if l.un != "" && l.un != newname {
		F单独压缩一个文件(l.un)
	}
	l.un = newname
	//打开新的日志文件，用于写入
	fp, err := os.OpenFile(l.un, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	log.SetOutput(fp)
	os.Stdout = nil
	os.Stdout = fp
	l.fp = fp
	return nil
}

// isDir 是否是目录
func IsDir(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return s.IsDir()
}

// dateToStr 时间转换为日期字符串
func dateToStr(t time.Time) string {
	return t.Format("2006-01-02")
}
